Skip to content

Conversation

@cfillion
Copy link
Contributor

@cfillion cfillion commented Jul 24, 2025

This adds a hook for backends to lookup fallback fonts from the user's system when encountering a missing glyph and merge them to the current ImFont on demand.

Demonstration

static const char *ResolveSystemFont(BackendDetails *, const ImWchar codepoint, unsigned int *index)
{
  return ...; // eg. using FontConfig or DirectWrite
}

static void LookupFallbackFont(ImFontAtlas *atlas, ImFont *font, const ImWchar codepoint)
{
  auto details {static_cast<BackendDetails *>(font->Sources.front()->UserData)};

  ImFontConfig cfg;
  cfg.UserData = details; // added as a convenience to quickly map ImFont -> backend impl details
  cfg.MergeTarget = font; // replaces `MergeMode = true` to merge with any font not just the last added one
  // zero or more sources may be added here (they'll be initialized across all baked instances as long as MergeTarget == font)
  if(const char *fallback_file {ResolveSystemFont(details, codepoint, &cfg.FontNo)})
    atlas->AddFontFromFileTTF(fallback_file, 0, &cfg);
}

void Setup()
{
  static auto loader {*ImGuiFreeType::GetFontLoader()};
  loader.FontAddFallbackSrc = &LookupFallbackFont;
  atlas->SetFontLoader(&loader);
}

Allows merging a new font with any other font in the same atlas instead of being restricted to merge with only the previously added font.
@ocornut
Copy link
Owner

ocornut commented Jul 29, 2025

I will definitively want to merge such feature, but I believe it needs to wait until I refactor font adding/loading functions and memory ownership, so I am putting to likely put that on hold for a bit.

There's actually a sort of "regression" in 1.92.0 as we keep font data in RAM and they may be loaded multiple times, which is an incredible waste. We are going to switch to a model where the library keeps a dictionary of unique data blob for fonts.

@cfillion
Copy link
Contributor Author

cfillion commented Jul 29, 2025

Also, since missing glyphs are cached per-baked font, it unnecessarily retries every time the font size changes (eg. auto-scaling). (Requiring the backend's fallback hook to do its own caching on top.)

Useful to retrieve backend-specific data needed to find an appropriate fallback for an ImFont.
@ocornut
Copy link
Owner

ocornut commented Aug 26, 2025

I will definitively want to merge such feature, but I believe it needs to wait until I refactor font adding/loading functions and memory ownership, so I am putting to likely put that on hold for a bit.

There's actually a sort of "regression" in 1.92.0 as we keep font data in RAM and they may be loaded multiple times, which is an incredible waste. We are going to switch to a model where the library keeps a dictionary of unique data blob for fonts.

Technically speaking this can likely be exposed with a simple flag e.g. ImFontFlags_DeferLoading but however the data source is loaded and referenced is the important backbone part of it. I imagine we might make a ImFontSrc be provided e.g a data pointer or a function callback.

I may get back to this sooner as I am presently trying to figure out which is the preferred order to tackle incoming font changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants